/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"
#include "EC_Ephemeral_fp.h"

#if CC_EC_Ephemeral  // Conditional expansion of this file

/*(See part 3 specification)
// This command creates an ephemeral key using the commit mechanism
*/
//  Return Type: TPM_RC
// TPM_RC_NO_RESULT             the TPM is not able to generate an 'r' value
/*
The TPM generates keys that have different lifetimes. TPM keys in a hierarchy can be persistent for as 
long as the seed of the hierarchy is unchanged and these keys may be used multiple times. 
Other TPMgenerated keys are only useful for a single operation. Some of these single-use keys are used in 
the command in which they are created. Examples of this use are TPM2_Duplicate() where an ephemeral key is 
created for a single pass key exchange with another TPM. However, there are other cases, such as anonymous 
attestation, where the protocol requires two passes where the public part of the ephemeral key is used 
outside of the TPM before the final command "consumes" the ephemeral key.
TPM 生成具有不同生命周期的密钥。 只要层次结构的种子不变并且这些密钥可以多次使用，层次结构中的 TPM 密钥就可以持久存在。
其他 TPM 生成的密钥仅对单个操作有用。 其中一些一次性密钥在创建它们的命令中使用。 这种用法的示例是 TPM2_Duplicate()，其中为与另一个 
TPM 的单次密钥交换创建了一个临时密钥。 但是，还有其他情况，例如匿名证明，其中协议需要两次通过，其中临时密钥的公共部分在最终命令“使用”
临时密钥之前在 TPM 外部使用。

For these uses, TPM2_Commit() or TPM2_EC_Ephemeral() may be used to have the TPM create an ephemeral EC key and 
return the public part of the key for external use. Then in a subsequent command, the caller provides a reference 
to the ephemeral key so that the TPM can retrieve or recreate the associated private key
对于这些用途，TPM2_Commit() 或 TPM2_EC_Ephemeral() 可用于让 TPM 创建临时 EC 密钥并返回密钥的公共部分以供外部使用。 然后在后续命令中，
调用者提供对临时密钥的引用，以便 TPM 可以检索或重新创建关联的私钥

When an ephemeral EC key is created, it is assigned a number and that number is returned to the caller as the 
identifier for the key. This number is not a handle. A handle is assigned to a key that may be context saved 
but these ephemeral EC keys may not be saved and do not have a full key context. When a subsequent command uses 
the ephemeral key, the caller provides the number of the ephemeral key.
The TPM uses that number to either look up or recompute the associated private key. After the key is used, the 
TPM records the fact that the key has been used so that it cannot be used again.
创建临时 EC 密钥时，会为其分配一个编号，并将该编号作为密钥的标识符返回给调用者。 这个数字不是句柄。 一个句柄被分配给一个可以保存上下文的密钥，
但这些临时 EC 密钥可能不会被保存并且没有完整的密钥上下文。 当后续命令使用临时密钥时，调用者提供临时密钥的编号。
TPM 使用该数字查找或重新计算关联的私钥。 密钥被使用后，TPM会记录密钥已经被使用过的事实，使其无法再次使用。

As mentioned, the TPM can keep each assigned private ephemeral key in memory until it is used.
However, this could consume a large amount of memory. To limit the memory size, the TPM is allowed to restrict the 
number of pending private keys – keys that have been allocated but not used.
如前所述，TPM 可以将每个分配的临时私钥保存在内存中，直到使用为止。
但是，这可能会消耗大量内存。 为了限制内存大小，TPM 被允许限制待处理私钥的数量——已分配但未使用的密钥。

NOTE The minimum number of ephemeral keys is determined by a platform specific specification.
To further reduce the memory requirements for the ephemeral private keys, the TPM is allowed to use pseudo-random
values for the ephemeral keys. Instead of keeping the full value of the key in memory, the TPM can use a counter as 
input to a KDF. Incrementing the counter will cause the TPM to generate a new pseudo-random value.
注意 临时密钥的最小数量由特定于平台的规范确定。
为了进一步减少临时私钥的内存需求，TPM 被允许对临时密钥使用伪随机值。 TPM 可以使用计数器作为 KDF 的输入，而不是将密钥的完整值保存在内存中。 
增加计数器将导致 TPM 生成一个新的伪随机值。

Using the counter to generate pseudo-random private ephemeral keys greatly simplifies tracking of key usage. When a 
counter value is used to create a key, a bit in an array may be set to indicate that the key use is pending. When the 
ephemeral key is consumed, the bit is cleared. This prevents the key from being used more than once.
Since the TPM is allowed to restrict the number of pending ephemeral keys, the array size can be limited.
For example, a 128 bit array would allow 128 keys to be "pending".
The management of the array is described in greater detail in the Split Operations clause in Annex C of TPM 2.0 Part 1.
使用计数器生成伪随机私有临时密钥极大地简化了对密钥使用情况的跟踪。 当计数器值用于创建密钥时，可以设置数组中的位以指示密钥使用待定。 当使用临时密钥时，
该位将被清除。 这可以防止密钥被多次使用。
由于允许 TPM 限制挂起的临时密钥的数量，因此可以限制数组大小。
例如，一个 128 位数组将允许 128 个键为“未决”。
数组的管理在 TPM 2.0 第 1 部分的附件 C 中的拆分操作条款中有更详细的描述。

*/
/*
tpm2_ecephemeral -u ecc.q -t ecc.ctr ecc256
内部生成临时ecc密钥对，公钥输出到 -u ecc.q
内部 counter 输出到 -t ecc.ctr（可用来在tpm中重新生成 ecc.q 对应的私钥）
*/
TPM_RC
TPM2_EC_Ephemeral(
    EC_Ephemeral_In     *in,            // IN: input parameter list
    EC_Ephemeral_Out    *out            // OUT: output parameter list
    )
{
    TPM2B_ECC_PARAMETER      r;
    TPM_RC                   result;
//
    do
    {
        // Get the random value that will be used in the point multiplications
        // Note: this does not commit the count.
        if(!CryptGenerateR(&r, NULL, in->curveID, NULL))
            return TPM_RC_NO_RESULT;
        // do a point multiply
        result = CryptEccPointMultiply(&out->Q.point, in->curveID, NULL, &r,
                                       NULL, NULL);
        // commit the count value if either the r value results in the point at
        // infinity or if the value is good. The commit on the r value for infinity
        // is so that the r value will be skipped.
        if((result == TPM_RC_SUCCESS) || (result == TPM_RC_NO_RESULT))
            out->counter = CryptCommit();
    } while(result == TPM_RC_NO_RESULT);

    return TPM_RC_SUCCESS;
}

#endif // CC_EC_Ephemeral